package com.nulldev.util.web.HttpServer3.extensions.envStats;

import java.util.Arrays;
import java.util.concurrent.ExecutorService;

import com.nulldev.util.JVM.Exceptions;
import com.nulldev.util.concurrency.threadIt.v4.emapi.ExecutorManager;
import com.nulldev.util.concurrency.threadIt.v4.emapi.IExecutorManager;
import com.nulldev.util.concurrency.threadIt.v4.emapi.extensions.ExecutorFeatureExtensions;
import com.nulldev.util.concurrency.threadIt.v4.emapi.extensions.ExtendedExecutor;
import com.nulldev.util.concurrency.threadIt.v4.emapi.extensions.ExtendedExecutor.EEXDebugQueryType;
import com.nulldev.util.concurrency.threadIt.v4.sched.ASyncScheduler;
import com.nulldev.util.concurrency.threadIt.v4.sched.ASyncScheduler.ASyncSchedulerDebugQuery;
import com.nulldev.util.languages.json.uniapi.UniJsonValue;
import com.nulldev.util.manage.nullUtil;
import com.nulldev.util.web.HttpServer3.Response;
import com.nulldev.util.web.HttpServer3.pages.v3.HttpPage3;

public class EMAPIStatsPage extends HttpPage3 {

	private static final String JSON_MIME = "application/json; charset=utf-8";

	public EMAPIStatsPage() {
		super("/debug/emapi");
	}

	@SuppressWarnings("resource")
	@Override
	public Response onRequest(final Request request) {
		if (!nullUtil.IS_NON_MAINLINE_BUILD)
			return new Response(204, BLANK_IO_STREAM);
		final UniJsonValue uv = UniJsonValue.object();
		final IExecutorManager em = ExecutorManager.get();
		final ExecutorService es = em.executor();
		final boolean isExtended = es instanceof ExtendedExecutor;
		uv.add("isExtendedExecutor", isExtended);
		uv.add("executor", es.toString());
		final ASyncScheduler ass = em.scheduler();
		uv.add("scheduler", ass.toString());
		if (ass != null && ass.supportsDebugQuery()) {
			final UniJsonValue sched = UniJsonValue.object();
			sched.add("QUEUE_SIZE", ass.debug_query(ASyncSchedulerDebugQuery.ASYNC_SCHED_DEBUG_QUEUE_SIZE));
			sched.add("L1_BATCHING_ACTIVE", ass.debug_query(ASyncSchedulerDebugQuery.ASYNC_SCHED_DEBUG_L1_BATCHING_ENABLED));
			sched.add("L2_BATCHING_ACTIVE", ass.debug_query(ASyncSchedulerDebugQuery.ASYNC_SCHED_DEBUG_L2_BATCHING_ENABLED));
			sched.add("L1_OPTIMIZATIONS_ACTIVE", ass.debug_query(ASyncSchedulerDebugQuery.ASYNC_SCHED_DEBUG_L1_OPTIMIZATIONS_ENABLED));
			sched.add("EXEC_BATCHING_ACTIVE", ass.debug_query(ASyncSchedulerDebugQuery.ASYNC_SCHED_DEBUG_EXECUTOR_BATCHING_SUPPORTED));
			uv.add("schedulerInfo", sched);
		}
		if (isExtended) {
			final ExtendedExecutor ex = ((ExtendedExecutor) es);
			final UniJsonValue extendedInfo = UniJsonValue.object();
			if (ex.supportsFeature(ExecutorFeatureExtensions.EEX_executor_low_priority_threads))
				extendedInfo.add("lpts", Arrays.toString(ex.getLPTs()));
			if (ex.supportsFeature(ExecutorFeatureExtensions.EEX_core_executor_slots))
				extendedInfo.add("slots", ex.executor_getFreeSlots());
			if (ex.supportsFeature(ExecutorFeatureExtensions.EEX_query_debug)) {
				final UniJsonValue queryDebug = UniJsonValue.object();
				queryDebug.add("ACTIVE_THREAD_COUNT", ex.debug_query(EEXDebugQueryType.EEX_DEBUG_ACTIVE_THREAD_COUNT));
				queryDebug.add("TOTAL_THREAD_COUNT", ex.debug_query(EEXDebugQueryType.EEX_DEBUG_TOTAL_THREAD_COUNT));
				final UniJsonValue _lpt = UniJsonValue.object();
				_lpt.add("LPT_ACTIVE", ex.debug_query(EEXDebugQueryType.EEX_DEBUG_LPT_ACTIVE));
				_lpt.add("LPT_ACTIVE_THREAD_COUNT", ex.debug_query(EEXDebugQueryType.EEX_DEBUG_LPT_ACTIVE_THREAD_COUNT));
				_lpt.add("LPT_TOTAL_THREAD_COUNT", ex.debug_query(EEXDebugQueryType.EEX_DEBUG_LPT_TOTAL_THREAD_COUNT));
				queryDebug.add("lpt", _lpt);
				queryDebug.add("TASKS_IN_QUEUE", ex.debug_query(EEXDebugQueryType.EEX_DEBUG_TASKS_IN_QUEUE));
				queryDebug.add("NON_STANDARD_DCTE_CHAINS", ex.debug_query(EEXDebugQueryType.EEX_DCTE_NON_STANDARD_BATCHING_CHAIN_SIZE));
				final StackTraceElement[][] x = (StackTraceElement[][]) ex.debug_query(EEXDebugQueryType.EEX_DEBUG_ACTIVE_TASKS_STACK_TRACE);
				if (x != null) {
					final UniJsonValue s = UniJsonValue.array(x.length);
					for (int i = 0; i < x.length; i++) {
						s.add(Exceptions.stackTraceToString(x[i]));
					}
					queryDebug.add("stackTraces", s);
				}
				extendedInfo.add("queryDebug", queryDebug);
			}
			final ExecutorFeatureExtensions[] exl = ex.supported();
			final UniJsonValue extensions = UniJsonValue.array(exl.length);
			extensions.addAll(exl);
			extendedInfo.add("extensions", extensions);
			uv.add("extendedInfo", extendedInfo);
		}
		return new Response(200, uv, uv).setCustomMime(JSON_MIME);
	}

}
